#include <iostream>
#include <fstream>
#include <vector>
#include <unordered_set>
#include "hnsw.hpp"
#include "vecs_io.hpp"
#include "bruteforce.hpp"

using namespace std;
using namespace MultipleHNSW;

int main() {
    const char *dataset_name = "siftsmall";
    const int M = 40;
    const int ef_construction = 100;
    const int random_seed = 100;
    const int n_index = 1;

    const int ef_search_config[3] = {50, 20, 5}; //start, stride, iter

    int n_query, top_k, n_base, data_dim;
    top_k = 10;

    vector<float *> data = read_data(dataset_name, n_query, top_k, n_base, data_dim);
    float *base = data[0];
    float *query = data[1];

    //build index
    printf("building index\n");
    vector<int> label_l(n_base);
    for (int i = 0; i < n_base; i++) {
        label_l[i] = i;
    }

    HNSW hnsw(data_dim, n_base, M, ef_construction, random_seed);
    hnsw.insert(base, label_l);
//    hnsw.test_graph();

    BruteForceSearch bfs(data_dim, n_base);
    bfs.insert(base);

    //每一个节点的neighbor与其nearest neighbor之比, 取最底层的图计算graph_quality
    //k 为nearest neighbor的数量
    int k = M * 2;
    vector<unordered_set<int>> gnd = bfs.search_knn(base, k, n_base);
    vector<vector<int>> graph = hnsw.hierarchical_graph_[0];
    double total_match = 0;
    for (int i = 0; i < n_base; i++) {
        int match = 0;
        vector<int> neighbor = graph[i];
        unordered_set<int> tmp_gnd = gnd[i];
        int neighbor_size = neighbor.size();
        for (int j = 0; j < neighbor_size; j++) {
            if (tmp_gnd.find(neighbor[j]) != tmp_gnd.end()) { //find
                match++;
            }
        }

        total_match += (double) match / neighbor.size();
    }

    double quality = 1.0 * total_match / n_base;

    printf("M %d, efConstruction %d, n_index %d, dataset %s, quality %.3f\n", M, ef_construction, n_index, dataset_name,
           quality);

    return 0;
}